package com.hmsm.server.base;

import java.io.Serializable;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.criterion.Projections;
import org.hibernate.metadata.ClassMetadata;
import org.springframework.orm.hibernate3.HibernateCallback;

import com.hmsm.server.util.QueryResult;
import com.hmsm.server.util.Util;

public abstract class BaseDao<T, ID extends Serializable> extends AbstractBaseDao<T, ID> {

	private static final Log log = LogFactory.getLog(BaseDao.class);

	public boolean info(Object obj, String message) {
		log.info("<<" + obj.getClass() + ":" + message + ">>");
		return true;
	}

	public boolean error(Object obj, String message) {
		log.error("<<" + obj.getClass() + ":" + message + ">>");
		return true;
	}

	/**
	 * 
	 *  @描述:保存对象信息
	 *  @方法名称:save
	 *  @作者:yaosq
	 *  @创建日期:2014-4-1 下午03:52:44 
	 *  @param object
	 *  @return
	 *
	 */
	public T save(T object) {
		this.getHibernateTemplate().save(object);
		return object;
	}

	/**
	 * 
	 *  @描述:更新对象信息
	 *  @方法名称:update
	 *  @作者:yaosq
	 *  @创建日期:2014-4-1 下午03:52:56 
	 *  @param object
	 *  @return
	 *
	 */
	public T update(T object) {
		this.getHibernateTemplate().update(object);
		return object;
	}

	/**
	 * 
	 *  @描述:删除对象数据
	 *  @方法名称:delete
	 *  @作者:yaosq
	 *  @创建日期:2014-4-1 下午03:53:07 
	 *  @param object
	 *  @return
	 *
	 */
	public boolean delete(T object) {
		this.getHibernateTemplate().delete(object);
		return true;
	}

	/**
	 * 
	 *  @描述:根据ID值删除对象
	 *  @方法名称:delete
	 *  @作者:yaosq
	 *  @创建日期:2014-4-1 下午03:53:51 
	 *  @param id
	 *
	 */
	public void delete(ID id) {
		this.delete(this.getById(id));
	}

	/**
	 * 
	 *  @描述:删除集合对象
	 *  @方法名称:deleteAll
	 *  @作者:yaosq
	 *  @创建日期:2014-4-1 下午03:54:01 
	 *  @param objectArr
	 *  @return
	 *
	 */
	public boolean deleteAll(List<T> objectArr) {
		this.getHibernateTemplate().deleteAll(objectArr);
		return true;
	}

	/**
	 * 
	 *  @描述:删除对象数据
	 *  @方法名称:delete
	 *  @作者:yaosq
	 *  @创建日期:2014-4-1 下午03:53:07 
	 *  @param object
	 *  @return
	 *
	 */
	public int delByExample(T object) {
		int count;
		
		String hql = "delete from " + object.getClass().getName() + " c ";
		List<Object> par = new ArrayList<Object>();

		// 获取对象的所有属性名称和值
		Map<String, Object> fieldAll = getPersistencePropertyMap(object);
		Iterator<Entry<String, Object>> it = fieldAll.entrySet().iterator();
		StringBuffer sb = new StringBuffer();
		boolean flg = true;
		while (it.hasNext()) {
			Entry<String, Object> entry = it.next();
			// 如果值不为null，那么赋值
			String key = entry.getKey();
			Object value = entry.getValue();
			if (value != null) {
				if (sb.length() != 0) {
					sb.append(" and");
				}
				if (flg) {
					sb.append(" where ");
					flg = false;
				}
				sb.append(" c.");
				sb.append(key);
				sb.append("='"+value+"' ");
				par.add(value);
			}
		}
		hql += sb.toString();
		Session session = getCurrentSession();
		Query query = session.createQuery(hql);
//		for(int i = 0;i<par.size();i++){
//			Object p = par.get(i);
//			if(p instanceof Integer){
//				q.setInteger(i, ((Integer)p).intValue());
//			}
//		}
		count = query.executeUpdate();
		session.close();
		return count;
	}

	/**
	 * 判断指定属性是否是持久化属性
	 * @param propertyName
	 * @return
	 */
	public <E> boolean isPersistentProperty(Class<E> clazz, String propertyName) {
		boolean result = false;
		ClassMetadata meta = getSessionFactory().getClassMetadata(clazz);
		if (meta != null) {
			if(meta.getIdentifierPropertyName().equals(propertyName)){
				result = true;
			}else{
				String[] properties = meta.getPropertyNames();
				if (properties!=null){
					for(String prop:properties){
						if (prop.equals(propertyName)){
							result = true;
							break;
						}
					}
				}
			}
		}

		return result;
	}
	
	/**
	 * 
	 *  @描述:获取当前对象数据集合
	 *  @方法名称:query
	 *  @作者:yaosq
	 *  @创建日期:2014-4-1 下午03:54:29 
	 *  @param object
	 *  @return
	 *
	 */
	public List<T> query(T object) {
		return query(object, null);
	}
	
	/**
	 * 
	 *  @描述:获取当前对象数据集合
	 *  @方法名称:query
	 *  @作者:yaosq
	 *  @创建日期:2014-4-1 下午03:54:29 
	 *  @param object
	 *  @return
	 *
	 */
	public List<T> query(T object, String order) {
		return query(object, order, null, null);
	}
	
	/**
	 * 
	 * @param object
	 * @param order
	 * @param startIndex
	 * @param maxCount
	 * @return
	 */
	public List<T> query(T object, String order, Integer pageNo, Integer pageSize) {
		String hql = " from " + object.getClass().getName() + " c ";
		List<Object> par = new ArrayList<Object>();

		StringBuffer sb = createHqlWhereByExample(object, par);
		if (order!=null&&order.length()>0){
			sb.append(" order by ");
			sb.append(order);
		}

		hql += sb.toString();
		Session session = getCurrentSession();
		Query query = session.createQuery(hql);
		for(int i = 0;i<par.size();i++){
			Object p = par.get(i);
			query.setParameter(i, p);
		}

		if (pageSize!=null&&pageSize >0) {
			int index = (pageNo - 1) * pageSize;
			query.setFirstResult(index);
			query.setMaxResults(pageSize);
		}
		@SuppressWarnings("unchecked")
		List<T> list = query.list();
		session.close();

		return list;
	}
	
	/**
	 * 
	 * @param object
	 * @param order
	 * @param startIndex
	 * @param maxCount
	 * @return
	 */
	public long queryCount(T object) {
		long count = -1;
		
		String hql = "select count(*) from " + object.getClass().getName() + " c ";
		List<Object> par = new ArrayList<Object>();

		StringBuffer sb = createHqlWhereByExample(object, par);

		hql += sb.toString();
		Session session = getCurrentSession();
		Query query = session.createQuery(hql);
		for(int i = 0;i<par.size();i++){
			Object p = par.get(i);
			query.setParameter(i, p);
		}
		count = (Long) query.uniqueResult();
		session.close();

		return count;
	}

	private StringBuffer createHqlWhereByExample(T object, List<Object> par) {
		// 获取对象的所有属性名称和值
		Map<String, Object> fieldAll = getPersistencePropertyMap(object);
		Iterator<Entry<String, Object>> it = fieldAll.entrySet().iterator();
		StringBuffer sb = new StringBuffer();
		boolean flg = true;
		while (it.hasNext()) {
			Entry<String, Object> entry = it.next();
			// 如果值不为null，那么赋值
			String key = entry.getKey();
			Object value = entry.getValue();
			if(isPersistentProperty(object.getClass(), key)&&value!=null){
				Class<?> valueClass = value.getClass();
				boolean processible = true;
				if (value instanceof Collection){
					processible = false;
					log.debug("isCollection");
				}else if (Collection.class.isAssignableFrom(valueClass)){
					processible = false;
					log.debug("isCollection");
				}else if(Set.class.isAssignableFrom(valueClass)){
					processible = false;
					log.debug("not Collection");
				}else if(List.class.isAssignableFrom(valueClass)){
					processible = false;
					log.debug("not Collection");
				}else if(ArrayList.class.isAssignableFrom(valueClass)){
					processible = false;
					log.debug("not Collection");
				}else if(Map.class.isAssignableFrom(valueClass)){
					processible = false;
					log.debug("is Map");
				}else if(String.class.isAssignableFrom(valueClass)){
					processible = ((String)value).length()>0;
				}else{
				}
				if(processible) {
					if (sb.length() != 0) {
						sb.append(" and");
					}
					if (flg) {
						sb.append(" where ");
						flg = false;
					}
					if(value instanceof String){
						sb.append(" c.");
						sb.append(key);
						sb.append(" like ?");
						par.add("%"+value+"%");
					}else {
						sb.append(" c.");
						sb.append(key);
						sb.append("=? ");
						par.add(value);
					}
				}
			}
		}
		
		return sb;
	}
	
	/**
	 * 
	 *  @描述:查询当前对象的所有数据
	 *  @方法名称:queryAll
	 *  @作者:yaosq
	 *  @创建日期:2014-4-1 下午03:55:40 
	 *  @return
	 *
	 */
	@SuppressWarnings("unchecked")
	public List<T> queryAll(){
		String hql = " from " + this.getPersistenceClass().getName();
		return getHibernateTemplate().find(hql);
	}
	
    /**
     * 
     *  @描述:根据当前ID获取当前类型数据集合
     *  @方法名称:getById
     *  @作者:yaosq
     *  @创建日期:2014-4-1 下午03:56:00 
     *  @param id
     *  @return
     *
     */
	public T getById(ID id) {
		return (T) this.getHibernateTemplate().get(this.getPersistenceClass(), id);
	}
	
    /**
     *  @描述:根据ID加载数据
     *  @方法名称:load
     *  @作者:yaosq
     *  @创建日期:2014-4-1 下午03:58:57 
     *  @param id
     *  @return
     *
     */
	public T load(ID id) {
		return (T) this.getHibernateTemplate().load(this.getPersistenceClass(), id);
	}

	/**
	 * 
	 *  @描述:获取对象的总数
	 *  @方法名称:getCount
	 *  @作者:yaosq
	 *  @创建日期:2014-4-1 下午03:59:32 
	 *  @return
	 *
	 */
	public int getCount() {
		Integer obj = getHibernateTemplate().execute(new HibernateCallback<Integer>() {
			public Integer doInHibernate(Session session) throws HibernateException, SQLException {
				Integer result = null;
				
				Criteria c = session.createCriteria(getPersistenceClass());
				c.setProjection(Projections.rowCount());
				session.close();
				result = (Integer) c.uniqueResult();
				return result;
			}
		});
		return Integer.parseInt(obj.toString());
	}

	/**
	 * 
	 *  @描述:返回查询的值，包括查询sum、counts等等
	 *  @方法名称:getRowCount
	 *  @作者:yaosq
	 *  @创建日期:2014-4-1 下午03:59:45 
	 *  @param hql
	 *  @return
	 *
	 */
	public Long getRowCount(String hql) {
		List<?> objList = getHibernateTemplate().find(hql);
		if (objList.size() == 0) {
			return (long) 0;
		} else {
			return (Long) objList.get(0);
		}
	}
    /**
     * 
     *  @描述:根据hql语句进行数据查询
     *  @方法名称:queryByHql
     *  @作者:yaosq
     *  @创建日期:2014-4-1 下午04:01:20 
     *  @param hql
     *  @return
     *
     */
	@SuppressWarnings("unchecked")
	public List<T> queryByHql(String hql) {
		return getHibernateTemplate().find(hql);
	}
	
	/**
     * @描述:根据hql语句进行数据查询
     * @方法名称:queryByHql
	 * @param hql
	 * @param n
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<T> queryByHql(String hql,int n) {
		getHibernateTemplate().setMaxResults(n);
		return getHibernateTemplate().find(hql);
	}

	/**
	 * hql翻页查询结果
	 *  @描述:
	 *  @方法名称 :queryPageList
	 *  @作者     :shu jun
	 *  @创建日期 :2014年4月10日 下午5:53:55 
	 *  @param hql
	 *  @param nowPage 当前页
	 *  @param maxresult 最大页
	 *  @return
	 *
	 */
	public List<T> queryPageList(String hql,int nowPage, int maxresult) {
		//初始分页数据
		if (nowPage < 1) {
			nowPage = 1;
		}
		Session session = getCurrentSession();
		Query query = session.createQuery(hql);

		if (maxresult >0) {
			int index = (nowPage - 1) * maxresult;
			query.setFirstResult(index);
			query.setMaxResults(maxresult);
		}
		@SuppressWarnings("unchecked")
		List<T> all = query.list();
		session.close();
		return all;
	}
	
	/**
	 * 
	 *  @描述:根据SQL和参数，返回查询的值，包括查询sum、counts等等
	 *  @方法名称:getQuerySqlIntValue
	 *  @作者:yaosq
	 *  @创建日期:2014-4-1 下午04:02:50 
	 *  @param sql
	 *  @return
	 *
	 */
	public double getQuerySqlIntValue(String sql) {
		final String hsql = sql;
		double value = (Double) getHibernateTemplate().execute(new HibernateCallback<Double>() {
			public Double doInHibernate(Session session) throws HibernateException, SQLException {
				SQLQuery query = session.createSQLQuery(hsql);  
				String str = query.uniqueResult().toString();  
				Util u = new Util();
				double value = 0;
				if(u.isNum(str)){
					value = Double.parseDouble(str);
				}
				session.close();
				return value;
			}
		});
		return value;
	}

	/**
	 * 
	 *  @描述:只支持SQL能够分装到Class对应的对象
	 *  @方法名称:queryBySql
	 *  @作者:yaosq
	 *  @创建日期:2014-4-1 下午04:03:02 
	 *  @param sql
	 *  @return
	 *
	 */
	public List<T> queryBySql(String sql) {
		Session session = getCurrentSession();
		Query queryObject = session.createSQLQuery(sql).addEntity(this.getPersistenceClass());
		@SuppressWarnings("unchecked")
		List<T> all = queryObject.list();
		session.close();
		return all;
	}
	
	/**
	 * 
	 *  @描述:
	 *  @方法名称 :getResultList
	 *  @作者     :shu jun
	 *  @创建日期 :2014年4月10日 下午5:35:14 
	 *  @param hql hql分页查询语句
	 *  @param countHql hql统计查询语句
	 *  @param nowPage 当前页
	 *  @param maxresult 每页数量
	 *  @return 分页查询结果集
	 *
	 */
	public QueryResult<T> getResultList(String hql,String countHql,int nowPage, int maxresult){
		//初始分页数据
		if (nowPage < 1) {
			nowPage = 1;
		}
		if (maxresult < 1) {
			maxresult = 30;
		}
		//获取查询结果的总数量
		int count = getRowCount(countHql).intValue();
		//分页查询数据
		Session session = getCurrentSession();
		Query query = session.createQuery(hql);
		int currPage = (nowPage - 1) * maxresult;
		query.setFirstResult(currPage);
		query.setMaxResults(maxresult);
		@SuppressWarnings("unchecked")
		List<T> all = query.list();
		session.close();
		
		//封装查询出的数据
		QueryResult<T> list = new QueryResult<T>();
		int allPages = (count - 1) / maxresult + 1; 
		list.setResultlist(all); 
		list.setAllPages(allPages);
		list.setNowPageNumber(nowPage);
		list.setNowViewRecordNumber(all.size());
		list.setPerPageNumber(maxresult);
		list.setTotalrecord(count);
		return list;
	}
	
	@SuppressWarnings("unchecked")
	public QueryResult<T> getScrollData(final Class<T> entityClass, final String idName, final int firstindex, final int maxresult, final String wherejpql, final Object[] queryParams, final LinkedHashMap<String, String> orderby) {
		
		QueryResult<T> qre = null;
		qre = (QueryResult<T>) getHibernateTemplate().execute(
				new HibernateCallback<QueryResult<T>>() {
					@Override
					public QueryResult<T> doInHibernate(Session session)
							throws HibernateException, SQLException {
						final String querySql = "select o from "
								+ entityClass.getName()
								+ " o "
								+ (wherejpql == null ? "" : "where "
										+ wherejpql + buildOrderby(orderby));
						final Query query = session.createQuery(querySql)
								.setCacheable(true);
						setQueryParams(query, queryParams);
						if (firstindex != -1 && maxresult != -1) {
							Integer nowindex = (firstindex - 1) * maxresult;
							query.setFirstResult(nowindex).setMaxResults(
									maxresult);
						}

						QueryResult<T> qr = new QueryResult<T>();
						qr.setResultlist(query.list());// 查询结果集
						qr.setNowViewRecordNumber(qr.getResultlist().size());// 当前显示的记录条数
						session.createQuery(querySql).setCacheable(true);
						final Query query2 = session
								.createQuery("select count(o."
										+ idName
										+ ") from "
										+ entityClass.getName()
										+ " o "
										+ (wherejpql == null ? "" : "where "
												+ wherejpql));
						setQueryParams(query2, queryParams);

						@SuppressWarnings("rawtypes")
						List list = query2.list();
						int lisre = list.size();
						if (lisre == 0) {
							qr.setTotalrecord(0L);
						} else {
							qr.setTotalrecord((Long)list.get(0));
						}

						qr.setNowPageNumber(firstindex);
						qr.setPerPageNumber(maxresult);
						long allPages = qr.getTotalrecord()
								/ qr.getPerPageNumber() + 1;
						if (qr.getTotalrecord() % qr.getPerPageNumber() == 0) {
							allPages -= 1;
						}
						qr.setAllPages(allPages);

						return qr;
					}
				});

		return qre;
	}	
	
	/**
	 * 组装order by语句
	 * 
	 * @param orderby
	 * @return
	 */
	protected String buildOrderby(LinkedHashMap<String, String> orderby) {
		StringBuffer orderbyql = new StringBuffer("");
		if (orderby != null && orderby.size() > 0) {
			orderbyql.append(" order by ");
			for (String key : orderby.keySet()) {
				orderbyql.append("o.").append(key).append(" ").append(
						orderby.get(key)).append(",");
			}
			orderbyql.deleteCharAt(orderbyql.length() - 1);
		}
		return orderbyql.toString();
	}	
	
	/**
	 * 设置参数
	 * 
	 * @param query
	 * @param queryParams
	 */
	protected void setQueryParams(Query query, Object[] queryParams) {
		if (queryParams != null && queryParams.length > 0) {
			for (int i = 0; i < queryParams.length; i++) {
				if (queryParams[i] == null) {
					query.setParameter(i, "");
				}else if (queryParams[i].equals("%null%")) {
					query.setParameter(i, "%%");
				}else {
					query.setParameter(i, queryParams[i]);
				}
			}
		}
	}
	
	/**
	 * 标准SQL语句查询，并返回list
	 * @return
	 */
	public List<List<String>> getSqlByCondition(final String sql){
		List<List<String>> obj = (List<List<String>>)getHibernateTemplate().execute(new HibernateCallback<List<List<String>>>() {
			public List<List<String>> doInHibernate(Session session) throws HibernateException, SQLException {
				@SuppressWarnings("unchecked")
				List<List<String>> list = session.createSQLQuery(sql).list();
				session.close();
				return list;
			}
		});
		return obj;
	}

	/**
	 * @描述： 得到分页数据 @创建人： JorisOuYang
	 * 
	 * @创建时间：2017年2月20日 上午11:18:16 @修改备注：
	 * @version
	 */
	@SuppressWarnings("unchecked")
	public List<T> getPageMessage(int nowPage,int pageNumber,T object){
		Session session = getCurrentSession();
		String hql = getHql(object);
		Query query = session.createQuery(hql);
		int begNumber = (nowPage-1)*pageNumber;
		query.setFirstResult(begNumber);
		query.setMaxResults(pageNumber);
		List<T> list = query.list();
		session.close();
		return list;
	}

	/**
	 * @描述： 得到Hql @创建人： JorisOuYang
	 * 
	 * @创建时间：2017年2月20日 上午11:38:46 @修改备注：
	 * @version
	 */
	public String getHql(T object){
		String hql = "from "+object.getClass().getName()+" c";
		Map<String, Object> map = getPersistencePropertyMap(object);
		Iterator<Entry<String, Object>> it = map.entrySet().iterator();
		StringBuffer sb = new StringBuffer();
		boolean judge = true;
		while(it.hasNext()){
			Entry<String, Object> et = it.next();
			String key = et.getKey();
			Object value = et.getValue();
			if(value != null){
				if(sb.length() != 0){
					sb.append(" and");
				}
				if(judge){
					sb.append(" where");
					judge = false;
				}
				sb.append(" c.");
				sb.append(key);
				sb.append(" = '"+value+"'");
			}
		}
		hql += sb.toString();
		return hql;
	}
	
	/**
	 * @描述： 得到总数
	 * @创建人： JorisOuYang
	 * @创建时间：2017年2月20日 下午1:57:28
	 * @修改备注：
	 * @version
	 */
	@SuppressWarnings("unchecked")
	public int getCounts(T object){
		int count = 0;
		
		String hql = "select count(*) "+getHql(object);
		List<Object> result = getHibernateTemplate().find(hql);
		if(result.size()>0){
			count = ((Long)result.get(0)).intValue();
		}

		return count;
	}
	
}
